package cn.xy.commons.util;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.Map;

/**
 * JWT工具
 *
 *  @author xy
 */
@Slf4j
public class JwtUtil {
    private JwtUtil() {
    }

    /**
     * 由字符串生成加密 key
     *
     * @return 加密key
     */
    private static SecretKey generalKey(String secret) {
        byte[] encodedKey = secret.getBytes();
        return new SecretKeySpec(encodedKey, SignatureAlgorithm.HS256.getJcaName());
    }


    /**
     * 创建 jwt
     *
     * @param claims    私有信息
     * @param subject   jwt 的主题
     * @param secret    jwt的密钥
     * @param ttlMillis jwt 的有效期
     * @return 生成的 jwt
     */
    public static String createJwt(Map<String, Object> claims, String subject, String secret, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey key = generalKey(secret);
        JwtBuilder builder = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setSubject(subject)
                .signWith(key, signatureAlgorithm);
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 解密 jwt
     *
     * @param secret jwt的密钥
     * @param jwt    要被解析的 Json Web Token
     * @return 若解析成功，则返回 Claims
     */
    public static Claims parseJwt(String secret, String jwt) throws MalformedJwtException {
        if (CharSequenceUtil.isEmpty(jwt)) {
            return Jwts.claims();
        }
        try {
            SecretKey key = generalKey(secret);
            return Jwts.parserBuilder()
                    .setSigningKey(key).build()
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (Exception e) {
            log.error("parse token error, e={}", e.getMessage());
            return Jwts.claims();
        }

    }

    public static boolean isExpired(Claims claims, String subject) {
        Date date = new Date();
        if (claims == null || claims.getSubject() == null || claims.getExpiration() == null) {
            return true;
        }
        return !claims.getSubject().equals(subject) || claims.getExpiration().before(date);
    }

    public static int getInteger(Claims claims, String key) {
        String value = JwtUtil.getString(claims, key);
        return NumberUtil.isNumber(value) ? Integer.parseInt(value) : 0;
    }

    public static String getString(Claims claims, String key) {
        return String.valueOf(claims.get(key));
    }
}
